package config;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;

import serverClient.ConfigChangeObserver;

public class Config implements ConfigInterface, ConfigChangeObserver {

	private final boolean DEBUG = false;

	private File configDir;
	private File configFile;

	private boolean newConfigFileCreated = false;

	private String skinType;
	private String guiType;
	private boolean visibleGui;
	private String lastConectionIP;
	private String lastSyncDoneMsg;
	private String ipAddress;
	private String directory;
	private String secondDir;
	private boolean localSync;
	private boolean startListen;
	private String syncMode;	
	private int sendPort;
	private int listenPort;
	private boolean autoSync;
	private int autoSyncDelay;
	private boolean allowDelete;
	private boolean deleteWarning;
	private boolean includeHidden;
	private boolean useExactTime;
	private boolean saveLog;

	private FileOutputStream out; // Declare a file output object
	private PrintStream pStream; // Declare a print stream object
	private FileReader in;
	private BufferedReader inBuf;

	public Config() {
		// Initialize ConfigDir
		configDir = new File(determenConfigFolder());
		if(!configDir.exists()) {
			configDir.mkdirs();
		}

		configFile = new File(configDir.getPath() + File.separator + "config.ini");
		if(!configFile.exists()) {
			newConfigFileCreated = true;
		}
		loadConfig();
	}

	public Config(String folderName) {
		// Initialize ConfigDir
		configDir = new File(folderName);
		if(!configDir.exists()) {
			configDir.mkdir();
		}

		configFile = new File(configDir.getPath() + File.separator + "config.ini");
		if(!configFile.exists()) {
			newConfigFileCreated = true;
		}
		loadConfig();
	}

	public String getConfigDir() {
		return configDir.getAbsolutePath();
	}

	public void setConfigDir(File confdir) {
		configDir = confdir;
	}

	public boolean getNewConfigFileCreated() {
		return newConfigFileCreated;
	}

	private String determenConfigFolder() {
		String path = "";
		try {
			path = System.getProperty("user.home");
		} catch (SecurityException e) {
			if(DEBUG) System.err.println("Could not find the home directory");
			path = (new File(".syncit")).getAbsolutePath();
			return path;
		}

		if(path.equals(null)) {
			path = (new File(".syncit")).getAbsolutePath();
			return path;
		}

		String os = System.getProperty("os.name").toUpperCase();
		// Windows
		if (os.indexOf("WIN") >= 0) {
			if( (new File(path + File.separator + "AppData" + File.separator + "Roaming")).exists() ) { // Windows Vista etc.
				path += File.separator + "AppData" + File.separator + "Roaming" + File.separator + "Sync IT";
			}
			else if( (new File(path + File.separator + "Application Data")).exists() ) { // Windows XP etc.
				path += File.separator + "Application Data" + File.separator + "Sync IT";
			}
			else { // Other Windows and local translations of Windows
				path += File.separator + ".syncit";
			}
		}
		// Mac
		else if (os.indexOf("MAC") >= 0) {
			path += File.separator + ".syncit";
		}
		// Linux and others Unix systems
		else {
			path += File.separator + ".syncit";
		}
		return path;
	}


	public void openFileForWriting() {
		try {
			out = new FileOutputStream(configFile);
			pStream = new PrintStream(out);

		} catch (Exception e) {
			if(DEBUG) System.err.println("File input error");
		}
	}

	public void closeFileAfterWriting() {
		try {
			pStream.close();
			out.close();

		} catch (Exception e) {
			if(DEBUG) System.err.println("Error closing file");
		}
	}

	public void openFileForReading() throws FileNotFoundException {

		in = new FileReader(configFile);
		inBuf = new BufferedReader(in);
	}

	public void closeFileAfterReading() {
		try {
			inBuf.close();
			in.close();
		} catch (IOException e) {
			if(DEBUG) System.err.println("Unable to close file avter writing");
			e.printStackTrace();
		}
	}



	public String getSkinType() {
		return skinType;
	}

	public void setSkinType(String skinType) {
		this.skinType = skinType;
	}

	public String getGuiType() {
		return guiType;
	}

	public void setGuiType(String guiType) {
		this.guiType = guiType;
	}

	public boolean getVisibleGui() {
		return visibleGui;
	}

	public void setVisibleGui(boolean visibleGui) {
		this.visibleGui = visibleGui;
	}

	public String getLastConectionIP() {
		return lastConectionIP;
	}

	public void setLastConectionIP(String lastConectionIP) {
		this.lastConectionIP = lastConectionIP;
	}

	public String getLastSyncDoneMsg() {
		return lastSyncDoneMsg;
	}

	public void setLastSyncDoneMsg(String lastSyncDoneMsg) {
		this.lastSyncDoneMsg = lastSyncDoneMsg;
	}

	public String getIPAddress() {
		return ipAddress;
	}

	public void setIPAddress(String iPAdd) {
		if(iPAdd.equals("")) {
			ipAddress = " ";
		}
		else {
			ipAddress = iPAdd;
		}
	}

	public String getDirectory() {
		return directory;
	}

	public void setDirectory(String directory) {
		this.directory = directory;
	}

	public String getSecondDir() {
		return secondDir;
	}

	public void setSecondDir(String secondDir) {
		this.secondDir = secondDir;
	}

	public boolean getLocalSync() {
		return localSync;
	}

	public void setLocalSync(boolean localSync) {
		this.localSync = localSync;
	}

	public boolean getStartListen() {
		return startListen;
	}

	public void setStartListen(boolean startListen) {
		this.startListen = startListen;
	}


	public String getSyncMode() {
		return syncMode;
	}

	public void setSyncMode(String syncMode) {
		this.syncMode = syncMode;
	}

	public int getSendPort() {
		return sendPort;
	}

	public void setSendPort(int sendPort) {
		this.sendPort = sendPort;
	}

	public int getListenPort() {
		return listenPort;
	}

	public void setListenPort(int listenPort) {
		this.listenPort = listenPort;
	}

	public boolean getAutoSync() {
		return autoSync;
	}

	public void setAutoSync(boolean autoSync) {
		this.autoSync = autoSync;
	}

	public int getAutoSyncDelay() {
		return autoSyncDelay;
	}

	public void setAutoSyncDelay(int autoSyncDelay) {
		this.autoSyncDelay = autoSyncDelay;
	}

	public boolean getAllowDelete() {
		return allowDelete;
	}

	public void setAllowDelete(boolean allowDelete) {
		this.allowDelete = allowDelete;
	}

	public boolean getDeleteWarning() {
		return deleteWarning;
	}

	public void setDeleteWarning(boolean deleteWarning) {
		this.deleteWarning = deleteWarning;
	}

	public boolean getIncludeHidden() {
		return includeHidden;
	}

	public void setIncludeHidden(boolean includeHidden) {
		this.includeHidden = includeHidden;
	}

	public boolean getUseExactTime() {
		return useExactTime;
	}

	public void setUseExactTime(boolean useExactTime) {
		this.useExactTime = useExactTime;
	}

	public boolean getSaveLog() {
		return saveLog;
	}

	public void setSaveLog(boolean saveLog) {
		this.saveLog = saveLog;
	}


	public void saveConfig() {
		if(DEBUG) System.out.println("Saving Config");
		configFile.delete();
		openFileForWriting();
		pStream.println( "SkinType=" + this.getSkinType() );
		pStream.println( "GuiType=" + this.getGuiType() );
		pStream.println( "VisibleGui=" + this.getVisibleGui() );
		pStream.println( "LastConIP=" + this.getLastConectionIP() );
		pStream.println( "LastSyncDoneMsg=" + this.getLastSyncDoneMsg() );
		pStream.println( "IP=" + this.getIPAddress() );
		pStream.println( "Directory=" + this.getDirectory() );
		pStream.println( "SecondDir=" + this.getSecondDir() );
		pStream.println( "LocalSync=" + this.getLocalSync() );
		pStream.println( "StartListen=" + this.getStartListen() );
		pStream.println( "SyncMode=" + this.getSyncMode() );
		pStream.println( "SendPort=" + this.getSendPort() );
		pStream.println( "ListenPort=" + this.getListenPort() );
		pStream.println( "AutoSync=" + this.getAutoSync() );
		pStream.println( "AutoSyncDelay=" + this.getAutoSyncDelay() );
		pStream.println( "AllowDelete=" + this.getAllowDelete() );
		pStream.println( "DeleteWarning=" + this.getDeleteWarning() );
		pStream.println( "IncludeHidden=" + this.getIncludeHidden() );
		pStream.println( "UseExactTime=" + this.getUseExactTime() );
		pStream.println( "SaveLog=" + this.getSaveLog() );
		closeFileAfterWriting();
	}

	public void loadConfig() {
		if(DEBUG) System.out.println("Reading Config");

		createDefaultConfigValues();

		try {
			openFileForReading();
			String line;
			String[] lineSplit = new String[2];
			while( (line = inBuf.readLine()) != null) {
				lineSplit = line.split("=");
				if(      lineSplit[0].equals("SkinType") )			skinType = lineSplit[1];
				else if( lineSplit[0].equals("GuiType") )			guiType = lineSplit[1];
				else if( lineSplit[0].equals("VisibleGui") )		visibleGui = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("LastConIP") )			lastConectionIP = lineSplit[1];
				else if( lineSplit[0].equals("LastSyncDoneMsg") )	lastSyncDoneMsg = lineSplit[1];
				else if( lineSplit[0].equals("IP") )				ipAddress = lineSplit[1];
				else if( lineSplit[0].equals("Directory") )			directory = lineSplit[1];
				else if( lineSplit[0].equals("SecondDir") )			secondDir = lineSplit[1];
				else if( lineSplit[0].equals("LocalSync") )			localSync = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("StartListen") )		startListen = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("SyncMode") )			syncMode = lineSplit[1];
				else if( lineSplit[0].equals("SendPort") )			sendPort = Integer.parseInt(lineSplit[1]);
				else if( lineSplit[0].equals("ListenPort") )		listenPort = Integer.parseInt(lineSplit[1]);
				else if( lineSplit[0].equals("AutoSync") )			autoSync = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("AutoSyncDelay") )		autoSyncDelay = Integer.parseInt(lineSplit[1]);
				else if( lineSplit[0].equals("AllowDelete") )		allowDelete = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("DeleteWarning") )		deleteWarning = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("IncludeHidden") )		includeHidden = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("UseExactTime") )		useExactTime = Boolean.parseBoolean(lineSplit[1]);
				else if( lineSplit[0].equals("SaveLog") )			saveLog = Boolean.parseBoolean(lineSplit[1]);
			}
			closeFileAfterReading();
		} catch (FileNotFoundException fe) {
			if(DEBUG) System.out.println("Config file not found");
		} catch (NullPointerException ne) {
			closeFileAfterReading();
		} catch (ArrayIndexOutOfBoundsException aie) {
			closeFileAfterReading();
		} catch (Exception e) {
			if(DEBUG) System.out.println("Something unexpected happened when reading from the config-file");
			closeFileAfterReading();
			e.printStackTrace();
		}
		if(DEBUG) System.out.println("Finished reading config values");
	}

	public void createDefaultConfigValues() {

		if(DEBUG) System.out.println("Creating default config values");

		skinType = "default";
		guiType = "simple";
		visibleGui = true;
		lastConectionIP = "never connected";
		lastSyncDoneMsg = " ; ";
		ipAddress = " ";
		directory = "Select a folder!";
		secondDir = "Select a folder!";
		localSync = false;
		startListen = false;
		syncMode = "dual";
		sendPort = 45326;
		listenPort = 45326;
		autoSync = false;
		autoSyncDelay = 300000;
		allowDelete = false;
		deleteWarning = true;
		includeHidden = false;
		useExactTime = false;
		saveLog = false;
	}



	// ConfigChangeObserver methods //

	public void changeConfigSyncMode(String syncMode) {
		this.syncMode = syncMode;
	}

	public void changeConfigIncludeHidden(boolean includeHidden) {
		this.includeHidden = includeHidden;
	}

	public void changeConfigUseExactTime(boolean useExactTime) {
		this.useExactTime = useExactTime;
	}

}
